
#include <BReadWrite>
#include <BStyle>
#include "member_BStyle.h"
#include "member_BObject.h"
#include "member_BWidget.h"
#include "IGlobal.h"

using namespace BWE;

#define member						(*(member_BStyle*)_ptr)
#define member_allocate()			_ptr = new member_BStyle(this)
#define member_release()			delete (member_BStyle*)_ptr

BStyle::BStyle(BStyle* parent)
{
	member_allocate();
	if (parent && parent != this)
		parent->addChild(this);
}
BStyle::BStyle(const BString& name, BStyle* parent) : BObject(name)
{
	member_allocate();
	if (parent && parent != this)
		parent->addChild(this);
}
BStyle::BStyle(const BColor& color, BStyle* parent)
{
	member_allocate();
	if (parent && parent != this)
		parent->addChild(this);
	member.init(color);
}
BStyle::BStyle(const BStyle& other) : BObject(other)
{
	member_allocate();
	member.valueMap = style_member(&other)->valueMap;
	member.colorMap = style_member(&other)->colorMap;
	member.imageMap = style_member(&other)->imageMap;
	member.iconMap = style_member(&other)->iconMap;

	member.namedFontMap = style_member(&other)->namedFontMap;
	member.namedColorMap = style_member(&other)->namedColorMap;
	member.namedImageMap = style_member(&other)->namedImageMap;
	member.namedIconMap = style_member(&other)->namedIconMap;

	member.transMap = style_member(&other)->transMap;
	member.subs = style_member(&other)->subs;
}
BStyle::~BStyle()
{
	member_release();
}

void BStyle::setType(const BString& type)
{
	member.type = type;
}
const BString& BStyle::type() const
{
	return member.type;
}

void BStyle::setHeritable(bool heritable)
{
	member.heritable = heritable;
}
bool BStyle::heritable() const
{
	return member.heritable;
}

void BStyle::setFont(BFont* font)
{
	member.namedFontMap[BString()] = font;
	member.dirty = true;
}
BFont* BStyle::font() const
{
	if (BFont* font = member.namedFontMap(BString()))
		return font;
	if (app_style && app_style != this)
		return app_style->font();
	return 0;
}

void BStyle::setFont(const BString& name, BFont* font)
{
	member.namedFontMap[name] = font;
}
const BFont* BStyle::font(const BString& name) const
{
	return member.namedFontMap(name);
}
BFont* BStyle::font(const BString& name)
{
	return member.namedFontMap(name);
}

void BStyle::setValue(StyleRole valueRole, const BValue& value)
{
	if (valueRole < 1)
		return;
	member.valueMap[valueRole] = value;
}
bool BStyle::removeVlaue(StyleRole valueRole)
{
	return member.valueMap.remove(valueRole);
}
const BValue& BStyle::value(StyleRole valueRole) const
{
	if (valueRole > 0)
	{
		auto it = member.valueMap.find(valueRole);
		if (it.valid())
			return *it;
		if (app_style && app_style != this)
			return app_style->value(valueRole);
	}
	return member.valueMap.def();
}

bool BStyle::setColor(StyleRole colorRole, BByte r, BByte g, BByte b, BByte a)
{
	if (colorRole < 1)
		return false;
	member.colorMap[colorRole].set(r, g, b, a);
	emit(Signal_Dirty);
	return true;
}
bool BStyle::setColor(StyleRole colorRole, const BColor& color)
{
	if (colorRole < 1)
		return false;
	member.colorMap[colorRole] = color;
	member.dirty = true;
	emit(Signal_Dirty);
	return true;
}
bool BStyle::removeColor(StyleRole colorRole)
{
	if (member.colorMap.remove(colorRole))
	{
		emit(Signal_Dirty);
		return true;
	}
	return false;
}
const BColor& BStyle::color(StyleRole colorRole) const
{
	if (colorRole > 0)
	{
		auto it = member.colorMap.find(colorRole);
		if (it.valid())
			return *it;
		if (app_style && app_style != this)
			return app_style->color(colorRole);
	}
	return member.colorMap.def();
}

bool BStyle::setImage(StyleRole imageRole, BImage* image)
{
	if (imageRole < 1)
		return false;
	member.imageMap[imageRole] = image;
	emit(Signal_Dirty);
	return true;
}
bool BStyle::removeImage(StyleRole imageRole)
{
	if (member.imageMap.remove(imageRole))
	{
		emit(Signal_Dirty);
		return true;
	}
	return false;
}
BImage* BStyle::image(StyleRole imageRole) const
{
	if (imageRole > 0)
	{
		auto it = member.imageMap.find(imageRole);
		if (it.valid())
			return *it;
		if (app_style != this && app_style)
			return app_style->image(imageRole);
	}
	return member.imageMap.def();
}

bool BStyle::setIcon(StyleRole iconRole, BIcon* icon)
{
	if (iconRole < 1)
		return false;
	member.iconMap[iconRole] = icon;
	emit(Signal_Dirty);
	return true;

}
bool BStyle::removeIcon(StyleRole iconRole)
{
	if (member.iconMap.remove(iconRole))
	{
		emit(Signal_Dirty);
		return true;
	}
	return false;
}
BIcon* BStyle::icon(StyleRole iconRole) const
{
	if (iconRole > 0)
	{
		auto it = member.iconMap.find(iconRole);
		if (it.valid())
			return *it;
		if (app_style && app_style != this)
			return app_style->icon(iconRole);
	}
	return member.iconMap.def();
}

bool BStyle::setTrans(const BString& word, const BString& trans)
{
	if (word.empty())
		return false;
	member.transMap[word] = trans;
	emit(Signal_Dirty);
	return true;
}
bool BStyle::removeTrans(const BString& word)
{
	if (member.transMap.remove(word))
	{
		emit(Signal_Dirty);
		return true;
	}
	return false;
}
const BString& BStyle::trans(const BString& text) const
{
	auto it = member.transMap.find(text);
	if (it.valid())
		return *it;
	if (app_style && app_style != this)
		return app_style->trans(text);
	return member.transMap.def();
}
bool BStyle::translate(const BString& text, BString& output) const
{
	output.reset();
	if (text.empty())
		return false;
	BString word = text;
	word.lower();
	word = this->trans(word);
	if (word.size())
	{
		output.append(word);
		return true;
	}
	int pos = 0;
	while (pos < text.size())
	{
		while (pos < text.size())
		{
			char code = text[pos];
			if (code > 0 && isalpha(text[pos]))
				break;
			output.append(text[pos]);
			pos++;
		}
		int end = pos;
		while (end < text.size())
		{
			char code = text[end];
			if (code > 0 && !isalpha(text[end]))
				break;
			end++;
		}
		if (end > pos)
		{
			word.reset(text, pos, end);
			word.lower();
			const BString& tw = this->trans(word);
			if (tw.size())
			{
				output -= ' ';
				output << tw;
			}
			else
			{
				output.append(text, pos, end);
			}
			pos = end;
		}
	}
	return output != text;
}
const BString& BStyle::translate(const BString& text) const
{
	static BString output;
	translate(text, output);
	return output;
}

bool BStyle::setColor(const BString& colorName, BByte r, BByte g, BByte b, BByte a)
{
	if (colorName.empty())
		return false;
	member.namedColorMap[colorName].set(r, g, b, a);
	emit(Signal_Dirty);
	return true;
}
bool BStyle::setColor(const BString& colorName, const BColor& color)
{
	if (colorName.empty())
		return false;
	member.namedColorMap[colorName] = color;
	emit(Signal_Dirty);
	return true;
}
bool BStyle::removeColor(const BString& colorName)
{
	if (member.namedColorMap.remove(colorName))
	{
		emit(Signal_Dirty);
		return false;
	}
	return true;
}
const BColor& BStyle::color(const BString& colorName) const
{
	if (colorName.size())
	{
		auto it = member.namedColorMap.find(colorName);
		if (it.valid())
			return *it;
		if (app_style && app_style != this)
			return app_style->color(colorName);
	}
	return member.namedColorMap.def();
}

bool BStyle::setImage(const BString& imageName, BImage* image)
{
	if (image)
	{
		member.namedImageMap[imageName] = image;
		emit(Signal_Dirty);
		return true;
	}
	return false;
}
bool BStyle::removeImage(const BString& imageName)
{
	if (member.namedImageMap.remove(imageName))
	{
		emit(Signal_Dirty);
		return true;
	}
	return false;
}
BImage* BStyle::image(const BString& imageName) const
{
	if (imageName.size())
	{
		auto it = member.namedImageMap.find(imageName);
		if (it.valid())
			return *it;
		if (app_style && app_style != this)
			return app_style->image(imageName);
	}
	return member.namedImageMap.def();
}

bool BStyle::setIcon(const BString& iconName, BIcon* icon)
{
	if (icon)
	{
		member.namedIconMap[iconName] = icon;
		emit(Signal_Dirty);
		return true;
	}
	return false;
}
bool BStyle::removeIcon(const BString& iconName)
{
	if (member.namedIconMap.remove(iconName))
	{
		emit(Signal_Dirty);
		return true;
	}
	return false;
}
BIcon* BStyle::icon(const BString& iconName) const
{
	if (iconName.size())
	{
		auto it = member.namedIconMap.find(iconName);
		if (it.valid())
			return *it;
		if (app_style && app_style != this)
			return app_style->icon(iconName);
	}
	return member.namedIconMap.def();
}

void BStyle::clearTrans()
{
	member.transMap.clear();
	emit(Signal_Dirty);
}
void BStyle::clearColors()
{
	member.colorMap.clear();
	member.namedColorMap.clear();
	emit(Signal_Dirty);
}
void BStyle::clearImages()
{
	member.imageMap.clear();
	member.namedImageMap.clear();
	emit(Signal_Dirty);
}
void BStyle::clearIcons()
{
	member.iconMap.clear();
	member.namedIconMap.clear();
	emit(Signal_Dirty);
}

bool BStyle::addSub(BStyle* style)
{
	if (!style)
		return false;
	member.subs.append(style);
	member.dirty = true;
	return true;
}
bool BStyle::removeSub(BStyle* style)
{
	if (member.subs.remove(style))
	{
		member.dirty = true;
		return true;
	}
	return false;
}
bool BStyle::clearSubs()
{
	member.subs.clear();
	return true;
}

int BStyle::subCount() const
{
	return member.subs.size();
}
BStyle* BStyle::sub(int index)
{
	return member.subs(index);
}
const BStyle* BStyle::sub(int index) const
{
	return member.subs(index);
}
BStyle* BStyle::sub(const BString& name)
{
	for (int i = 0; i < member.subs.size(); i++)
	{
		BStyle* sub = member.subs[i];
		if (sub->name() != name)
			continue;
		return sub;
	}
	return 0;
}
const BStyle* BStyle::sub(const BString& name) const
{
	for (int i = 0; i < member.subs.size(); i++)
	{
		BStyle* sub = member.subs[i];
		if (sub->name() != name)
			continue;
		return sub;
	}
	return 0;
}
BStyle* BStyle::sub(const char* name)
{
	for (int i = 0; i < member.subs.size(); i++)
	{
		BStyle* sub = member.subs[i];
		if (sub->name() != name)
			continue;
		return sub;
	}
	return 0;
}
const BStyle* BStyle::sub(const char* name) const
{
	for (int i = 0; i < member.subs.size(); i++)
	{
		BStyle* sub = member.subs[i];
		if (sub->name() != name)
			continue;
		return sub;
	}
	return 0;
}

bool BStyle::addChild(BStyle* child)
{
	if (!child)
		return false;
	if (child && this != child && !member.children.contain(child))
	{
		member.children.append(child);
		member.dirty = true;
		return true;
	}
	return false;
}
bool BStyle::removeChild(BStyle* child)
{
	if (member.children.remove(child))
	{
		member.dirty = true;
		return true;
	}
	return false;
}
bool BStyle::clearChildren()
{
	member.children.clear();
	return true;
}

int BStyle::childCount() const
{
	return member.children.size();
}
BStyle* BStyle::child(int index)
{
	return member.children(index);
}
const BStyle* BStyle::child(int index) const
{
	return member.children(index);
}
BStyle* BStyle::child(const BString& type, const BString& name)
{
	for (int i = 0; i < member.children.size(); i++)
	{
		BStyle* child = member.children[i];
		if (child->name() != name)
			continue;
		if (child->type() != type)
			continue;
		return child;
	}
	return 0;
}
const BStyle* BStyle::child(const BString& type, const BString& name) const
{
	for (int i = 0; i < member.children.size(); i++)
	{
		BStyle* child = member.children[i];
		if (child->name() != name)
			continue;
		if (child->type() != type)
			continue;
		return child;
	}
	return 0;
}

bool BStyle::input(const BString& text, const BValue& value)
{
	return BObject::input(text, value);
}
bool BStyle::query(const BString& text, BValue& value) const
{
	if (text == "value-map")
	{
		BMap<StyleRole, BValue>& valueMap = value.fill<BMap<StyleRole, BValue>>();
		valueMap = member.valueMap;
		return true;
	}
	if (text == "color-map")
	{
		BMap<StyleRole, BColor>& colorMap = value.fill<BMap<StyleRole, BColor>>();
		colorMap = member.colorMap;
		return true;
	}
	if (text == "image-map")
	{
		BMap<StyleRole, BImage*>& imageMap = value.fill<BMap<StyleRole, BImage*>>();
		imageMap = member.imageMap;
		return true;
	}
	if (text == "icon-map")
	{
		BMap<StyleRole, BIcon*>& iconMap = value.fill<BMap<StyleRole, BIcon*>>();
		iconMap = member.iconMap;
		return true;
	}
	if (text == "trans-map")
	{
		BMap<BString, BString>& transMap = value.fill<BMap<BString, BString>>();
		transMap = member.transMap;
		return true;
	}
	if (text == "named-value-map")
	{
		BMap<BString, BColor>& namedColorMap = value.fill<BMap<BString, BColor>>();
		namedColorMap = member.namedColorMap;
		return true;
	}
	if (text == "named-image-map")
	{
		BMap<BString, BImage*>& namedImageMap = value.fill<BMap<BString, BImage*>>();
		namedImageMap = member.namedImageMap;
		return true;
	}
	if (text == "named-icon-map")
	{
		BMap<BString, BIcon*>& namedIconMap = value.fill<BMap<BString, BIcon*>>();
		namedIconMap = member.namedIconMap;
		return true;
	}
	if (text == "subs")
	{
		BStyleArray& subs = value.fill<BStyleArray>();
		subs = member.subs;
		return true;
	}
	if (text == "children")
	{
		BStyleArray& children = value.fill<BStyleArray>();
		children = member.children;
		return true;
	}
	return BObject::query(text, value);
}

